package com.cn.controller;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.stream.*;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.sound.midi.Track;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;

@RestController
@RequestMapping("/unlock")
public class RedisUnlockController {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private static final String KEY_PREFIX = "lock";
    private static final String ID_PREFIX = UUID.randomUUID().toString()+"-";

    //订单添加到阻塞队列中
    private BlockingQueue<String> order_queue = new ArrayBlockingQueue<>(1024*1024);

    private static final ExecutorService order_executo = Executors.newSingleThreadExecutor();

    @PostConstruct
    public void init(){
        order_executo.submit(new placeOrder());
    }

    /**
     * 开启异步线程下单
     */
    private class placeOrder implements Runnable{
        @Override
        public void run() {
            while (true){
                try {
                    String take = order_queue.take();
                    System.out.println("创建订单成功"+take);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
        }
    }

    public boolean tryLock(long timeoutSec){
        //1,获取线程标识
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        //2.获取锁的方式
        Boolean sucess = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX,threadId,timeoutSec, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(sucess);
    }

    public void unlock(){
        String thread = ID_PREFIX + Thread.currentThread().getId();
        String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX);
        if (thread.equals(id)) {
            stringRedisTemplate.delete(KEY_PREFIX);
        }
    }

    @GetMapping("/unlockRedis")
    public Object unlockRedis(){
        tryLock(10l);
        unlock();
        return "成功";
    }
    @GetMapping("/testRedisson")
    public Object testRedisson() throws InterruptedException {
        //获取锁(可重入)，指定锁的名称
        RLock lock = redissonClient.getLock("anyLock");
        //尝试获取锁，参数分别是：获取锁的最大等待时间(期间会重试)，锁自动释放时间，时间单位
        boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS);
        //判断获取锁成功
        if (isLock) {
            try {
                System.out.println("执行业务");
            } finally {
                //释放锁
                lock.unlock();
            }
        }
        return "成功";
    }

    /**
     * 判断是否具有购买资格
     * @return
     */
    @GetMapping("/orderSuccess")
    public Object orderSuccess(String name){
        //1.一人一单
        order_queue.add(name);
        return "成功";
    }


    @GetMapping("/redisGroup")
    public Object redisGroup(){
        String queueName = "order";
        List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream()
                .read(
                        Consumer.from("g1", "c1"),
                        StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),
                        StreamOffset.create(queueName, ReadOffset.lastConsumed())
                );
        if (list ==null || list.isEmpty()){
            System.out.println("数据为空");
        }
        MapRecord<String, Object, Object> record = list.get(0);
        Map<Object, Object> value = record.getValue();
        System.out.println(value);
        return value;
    }

    /**
     * 测试异步阻塞队列的方式
     * @return
     */
    @GetMapping("/testRun")
    public Object testRun(){
        BlockingQueue<String> stringBlockingQueue = new ArrayBlockingQueue<>(1024*1024);
        stringBlockingQueue.add("我的方式");
        init();
        return "成功";
    }


}
